#include <math.h>
#include <iostream>
#include <set>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::multiset;
using std::pair;
using std::vector;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem << "  ";
    }
    cout << endl;
}

void test()
{
    //multiset的特征
    //1、key值是不唯一的，可以重复
    //2、默认情况下，会按照key值升序排列
    //3、multiset的底层使用的是红黑树数据结构

    multiset<int> number = {1, 3, 5, 5, 7, 5, 9, 2, 4};
    /* multiset<int, std::greater<int>> */ 
    /*     number = {1, 3, 5, 5, 7, 5, 9, 2, 4}; */
    display(number);

    cout << endl << "multiset中的查找" << endl;
    size_t cnt1 = number.count(5);
    cout << "cnt1 = " << cnt1 << endl;

    cout << endl;
    /* multiset<int>::const_iterator it = number.find(10); */
    multiset<int>::iterator it = number.find(10);
    if(it == number.end())//迭代器判空的独特方法
    {
        cout << "该元素不存在multiset中，查找失败" << endl;
    }
    else
    {
        cout << "该元素存在multiset中" << *it << endl;
    }

    cout << endl << "测试set的bound函数"  << endl;
    multiset<int>::iterator it2 = number.lower_bound(5);
    cout << "*it2 = " << *it2 << endl;

    multiset<int>::iterator it3 = number.upper_bound(5);
    cout << "*it3 = " << *it3 << endl;
    while(it2 != it3)
    {
        cout << *it2 << "  ";
        ++it2;
    }
    cout << endl;

    /* std::pair<multiset<int>::iterator, multiset<int>::iterator> */
    /*     ret = number.equal_range(5); */
    auto ret = number.equal_range(5);
    while(ret.first != ret.second)
    {
        cout << *ret.first << "  ";
        ++ret.first;
    }
    cout << endl;


    cout << endl << "multiset的insert操作" << endl;
    /* auto it2 = number.insert(8);//ok */
    number.insert(8);
    display(number);

    cout << endl << endl;
    vector<int> vec = {1, 3, 7, 9, 11, 45, 7, 9, 5, 7};
    number.insert(vec.begin(), vec.end());
    display(number);

    cout << endl << endl;
    number.insert({13, 56, 78, 23, 11, 14});
    display(number);

    cout << endl << "multiset的下标操作" << endl;
    //multiset是不支持下标的
    /* cout << "number[1] = " << number[1] << endl; */

    cout << endl << "multiset的修改操作" << endl;
    it = number.end();
    --it;
    --it;
    cout << "*it = " << *it << endl;
    /* *it = 123;//error, 不能修改 */
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
        /* cout << "Point(int = 0, int = 0)" << endl; */
    }

    double getDistance() const
    {
        return hypot(_ix, _iy);
    }

    void print() const
    {
        cout << "(" << _ix 
             << ", " << _iy
             << ")";
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
        /* cout << "~Point()" << endl; */
    }

    friend std::ostream &operator<<(std::ostream &os, const Point &rhs);
    friend bool operator<(const Point &lhs, const Point &rhs);
    friend bool operator>(const Point &lhs, const Point &rhs);
    friend struct Comparetion;//设计为了Point友元

private:
    int _ix;
    int _iy;
};

std::ostream &operator<<(std::ostream &os, const Point &rhs)
{
    os << "(" << rhs._ix 
       << ", " << rhs._iy
       << ")";

    return os;
}

bool operator<(const Point &lhs, const Point &rhs)
{
    cout << "bool operator<(const Point &, const Point &)" << endl;
    if(lhs.getDistance() < rhs.getDistance())
    {
        return true;
    }
    else if(lhs.getDistance() == rhs.getDistance())
    {
        if(lhs._ix < rhs._ix)
        {
            return true;
        }
        else if(lhs._ix == rhs._ix)
        {
            if(lhs._iy < rhs._iy)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

//函数对象
struct Comparetion
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout << "bool Comparetion::operator()()" << endl;
        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())
        {
            if(lhs._ix < rhs._ix)
            {
                return true;
            }
            else if(lhs._ix == rhs._ix)
            {
                if(lhs._iy < rhs._iy)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }

    }
};

//命名空间的扩展
namespace std
{

//模板的特化
template <>
struct less<Point>
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout << "bool std::less::operator()()" << endl;
        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())
        {
            if(lhs.getX() < rhs.getX())
            {
                return true;
            }
            else if(lhs.getX() == rhs.getX())
            {
                if(lhs.getY() < rhs.getY())
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }

    }
};

}//end of namespace std

bool operator>(const Point &lhs, const Point &rhs)
{
    cout << "bool operator>(const Point &, const Point &)" << endl;
    if(lhs.getDistance() > rhs.getDistance())
    {
        return true;
    }
    else if(lhs.getDistance() == rhs.getDistance())
    {
        if(lhs._ix > rhs._ix)
        {
            return true;
        }
        else if(lhs._ix == rhs._ix)
        {
            if(lhs._iy > rhs._iy)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}
void test2()
{
    /* multiset<Point> number = { */
    /* multiset<Point, std::less<Point>> number = { */
    multiset<Point, Comparetion> number = {
    /* multiset<Point, std::greater<Point>> number = { */
        Point(-1, 2),
        Point(1, -2),
        Point(1, 2),
        Point(2, -2),
        Point(3, 5),
        Point(1, 2)
    };

    display(number);
}

int main(int argc, char **argv)
{
    test2();
    return 0;
}

